#include "EPaper.hpp"
#include "supports.h"
#include <cstring>

static const uint8_t initSequences[159] =
{
0x80,0x66,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x0,
0x10,0x66,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,
0x80,0x66,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x0,
0x10,0x66,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x14,0x8,0x0,0x0,0x0,0x0,0x1,
0xA,0xA,0x0,0xA,0xA,0x0,0x1,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x14,0x8,0x0,0x1,0x0,0x0,0x1,
0x0,0x0,0x0,0x0,0x0,0x0,0x1,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x44,0x44,0x44,0x44,0x44,0x44,0x0,0x0,0x0,
0x22,0x17,0x41,0x0,0x32,0x36
};

EPaper::EPaper(IODevice *bus,Pin *nss,Pin *dc,Pin *reset,Pin *busy,int width,int height){
    this->width = width;
    this->height = height;
    this->bus = bus;
    this->nss = nss;
    this->dc = dc;
    this->rst = reset;
    this->busy = busy;

    /* 创建缓冲区 */
    this->framebuffer = new unsigned char [this->width * ( (this->height % 8) == 0 ? this->height / 8 : (this->height / 8) + 1)];
    std::memset(this->framebuffer,0xff,this->width * ( (this->height % 8) == 0 ? this->height / 8 : (this->height / 8) + 1));
    /* 执行初始化序列 */
    this->init();
}

EPaper::~EPaper(){
    if ( this->framebuffer != nullptr ){
        delete this->framebuffer;
        this->framebuffer = nullptr;
    }
}

void EPaper::setPixel(int x,int y,Color color){
    if ( x >= this->width || y >= this->height ) return;
    y = this->height - y;
    if ( color.data == 0x00 ){
        this->framebuffer[x * ( this->height / 8) + ( y / 8 ) ] |= (0x80 >> (y % 8));
    }else{
        this->framebuffer[x * ( this->height / 8) + ( y / 8 ) ] &=~ (0x80 >> (y % 8));
    }
}

Color EPaper::getPixel(int x,int y){
    Color color = {.data = 0};
    if ( x >= this->width || y >= this->height ) return color;
    y = this->height - y;
    if ( this->framebuffer[x * ( this->height / 8) + ( y / 8 ) ] & (0x80 >> (y % 8)) ){
        color.data = 1;
        return color;
    }else{
        color.data = 0;
        return color;
    }
}

void EPaper::setColumn(int column,int row,unsigned char data){
    int nrow = ( (this->height % 8) == 0 ? this->height / 8 : (this->height / 8) + 1);
    if ( column >= this->width || row >= nrow ) return;
    this->framebuffer[(column * nrow) + (nrow - row - 1)] = ~data;
}

unsigned char EPaper::getColumn(int column,int row){
    int nrow = ( (this->height % 8) == 0 ? this->height / 8 : (this->height / 8) + 1);
    if ( column >= this->width || row >= nrow ) return 0x00;
    return ~this->framebuffer[(column * nrow) + (nrow - row - 1)];
}

void EPaper::init(){
    this->reset();
    this->waitBusy();
    this->sendCommand(0x12);
    this->waitBusy();

    this->sendCommand(0x01);
    this->sendData(0x27);
    this->sendData(0x01);
    this->sendData(0x00);
    
    this->sendCommand(0x11);
    this->sendData(0x03);

    this->sendCommand(0x44);
    this->sendData((0x00 >> 3) & 0xff);
    this->sendData(((this->height - 1) >> 3) & 0xff);
    this->sendCommand(0x45);
    this->sendData(0x00);
    this->sendData(0x00);
    this->sendData((this->width - 1) & 0xff);
    this->sendData(((this->width - 1) >> 8) & 0xff);
    this->sendCommand(0x21);
    this->sendData(0x00);
    this->sendData(0x80);
    this->sendCommand(0x4e);
    this->sendData(0x00);
    this->sendCommand(0x4f);
    this->sendData(0x00);
    this->sendData(0x00);
    this->waitBusy();
    this->sendCommand(0x32);
    for ( int n = 0; n < 153; n++ ){
        this->sendData(initSequences[n]);
    }

}

void EPaper::refresh(){
    unsigned char *pframebuffer = this->framebuffer;
    this->sendCommand(0x24);
    for ( int npixel = 0; npixel < (this->width * ( (this->height % 8) == 0 ? this->height / 8 : (this->height / 8) + 1)); npixel++ ){
        this->sendData(*pframebuffer++);
    }
    this->sendCommand(0x22);
    this->sendData(0xc7);
    this->sendCommand(0x20);
    this->waitBusy();
}

void EPaper::sleep(){
    this->sendCommand(0x10);
    this->sendCommand(0x01);
}

void EPaper::waitBusy(){
    while ( this->busy->read() ){
        /* 超时判定与处理 */
    }
}

void EPaper::reset(){
    this->rst->write(1);
    Sys_delayMs(200);
    this->rst->write(0);
    Sys_delayMs(2);
    this->rst->write(1);
    Sys_delayMs(200);
}

void EPaper::clear(){
    this->sendCommand(0x24);
    for ( int npixel = 0; npixel < (this->width * ( (this->height % 8) == 0 ? this->height / 8 : (this->height / 8) + 1)); npixel++ ){
        this->sendData(0xff);
    }
    /* 刷新屏幕 */
    this->sendCommand(0x22);
    this->sendData(0xc7);
    this->sendCommand(0x20);
    this->waitBusy();
}

void EPaper::sendCommand(unsigned char command){
    this->dc->write(0);
    this->nss->write(0);
    this->bus->write(&command,1);
    this->nss->write(1);
}

void EPaper::sendData(unsigned char data){
    this->dc->write(1);
    this->nss->write(0);
    this->bus->write(&data,1);
    this->nss->write(1);
}



